package com.hyuk.hyukfgw.listener;

import com.hyuk.hyukfgw.framework.cache.util.RedisUtils;
import com.hyuk.hyukfgw.runner.Bootstrap;
import com.hyuk.hyukfgw.service.ops.bean.OpsChangeMsg;
import com.hyuk.hyukfgw.util.consts.OpsChangeConsts;
import com.hyuk.hyukfgw.util.excp.FgwCodeEnum;
import com.hyuk.hyukfgw.util.excp.FgwException;
import com.hyuk.hyukfgw.util.json.JacksonUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <h1>Junit 样例测试。</h1><br/>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2023/9/10 19:26
 */
@Slf4j
@SpringBootTest(classes = Bootstrap.class)
public class OpsChangeTest {
    
    private static Map<Integer, OpsChangeExecutor> opsChangeExecutorMap;
    
    @BeforeAll
    public static void init() {
        opsChangeExecutorMap = new HashMap<>(2);
        JdkOpsChangeExecutor jdkOpsChangeExecutor = new JdkOpsChangeExecutor();
        opsChangeExecutorMap.put(jdkOpsChangeExecutor.getType(), jdkOpsChangeExecutor);
        
        SpringBeanOpsChangeExecutor springBeanOpsChangeExecutor = new SpringBeanOpsChangeExecutor();
        opsChangeExecutorMap.put(springBeanOpsChangeExecutor.getType(), springBeanOpsChangeExecutor);
    }

    /**
     * <h2>Ops 键值对改变事件。</h2>
     *
     * @throws
     * @param key 配置中心监听到改变的 key
     * @param value 内容 {@link }
     * @return void
     * @author hmilyylimh
     * @date 2023/9/10
     */
    public void onChange(String key, String value) {
        // 0. 不是相关 Ops Change key 不处理
         if (!key.equals(OpsChangeConsts.LISTENER_KEY)) { return; }
        
        // 1. 参数转换
        OpsChangeMsg opsChangeMsg = JacksonUtils.fromJson(value, OpsChangeMsg.class);
        if (opsChangeMsg == null) { throw new FgwException(FgwCodeEnum.ARGS_ERROR); }
        
        // 2. 获取执行器, 如果未知的执行期报错
        OpsChangeExecutor opsChangeExecutor = opsChangeExecutorMap.get(opsChangeMsg.getExecutorType());
        if (opsChangeExecutor == null) {
            log.warn("未知的执行期类型, executorType : {}, methodName ; {}", opsChangeMsg.getExecutorType(), opsChangeMsg.getMethodName());
            throw new FgwException(FgwCodeEnum.ARGS_ERROR);
        }
        
        // 3、 执行
        Object returnVal = opsChangeExecutor.execute(opsChangeMsg);
        log.info("[OpsChangeTest][onChange]方法执行完成, className : {}, methodName : {}, returnVal : {}",
                opsChangeMsg.getClassName(), opsChangeMsg.getMethodName(), returnVal);
    }
    
    @Test
    public void testOnChange() {
        // 情况1: JDK-无参数
        String value = "{\"className\":\"com.hyuk.hyukfgw.biz.controller.auth.login.LoginByAccountPwdAction\",\"methodName\":\"test\",\"executorType\":1}";
        onChange(OpsChangeConsts.LISTENER_KEY, value);
        
        // 情况2: Spring Bean-无参数
        value = "{\"className\":\"com.hyuk.hyukfgw.biz.controller.auth.login.LoginByAccountPwdAction\",\"methodName\":\"test\",\"executorType\":2}";
        onChange(OpsChangeConsts.LISTENER_KEY, value);
        
        // 情况3: JDK-有参数
        value = "{\"className\":\"com.hyuk.hyukfgw.biz.controller.auth.login.LoginByAccountPwdAction\",\"methodName\":\"login\",\"parametersTypeList\":[\"com.hyuk.hyukfgw.facade.auth.login.LoginByAccountPwdRequest\",\"java.lang.String\"],\"parametersValueList\":[{\"account\":\"test_account\",\"password\":\"test_password\"},\"testString1\"],\"executorType\":1}";
        onChange(OpsChangeConsts.LISTENER_KEY, value);
        
        // 情况4: Spring-Bean 有参数
        value = "{\"className\":\"com.hyuk.hyukfgw.biz.controller.auth.login.LoginByAccountPwdAction\",\"methodName\":\"login\",\"parametersTypeList\":[\"com.hyuk.hyukfgw.facade.auth.login.LoginByAccountPwdRequest\",\"java.lang.String\"],\"parametersValueList\":[{\"account\":\"test_account\",\"password\":\"test_password\"},\"testString2\"],\"executorType\":2}";
        onChange(OpsChangeConsts.LISTENER_KEY, value);
        
        RedisUtils.set("test:key:01", "1_1", 1, TimeUnit.MINUTES);
    }
}